package si.assign1.model;

import java.io.Serializable;
import java.sql.Clob;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import java.sql.Clob;

@Entity
@Table(name="products")
@NamedQueries( {
    @NamedQuery(name="listProducts",
                query="SELECT p FROM Product p"),
    @NamedQuery(name="getProductById",
                query="SELECT p FROM Product p WHERE p.id = :id"),
    @NamedQuery(name="getProductByName",
                query="SELECT p FROM Product p WHERE p.name = :name")
})
public class Product 
{
	 public Product(){}
	 
	 public boolean equalsById(Product that) {
		 return this.id == that.id;
	 }
	 
	 /*
	  * Properties
	  */
	 
	 /*
	  * Set and get id
	  */
	 public int getId() 
	 {   return id;   }
	 public void setId(int id)
	 {   this.id = id; }

	 /*
	  * Set and get name
      */
	 public String getName()
	 {   return name;   }
	 public void setName(String name)
	 {   this.name = name;  }
	 
	 /*
	  * Set and get stock keeping unit
	  */
	 public String getSku()
	 {   return sku;  }
	 public void setSku(String sku)
	 {   this.sku = sku;  }
	 
	 /*
	  * Set and get description
      */
	 public String getDescription()
	 {   return description;   }
	 public void setDescription(String description)
	 {   this.description = description;  }
	
	 /*
	  * Set and get the on-hand property
	  */
	 public int getOnHand() {
		 return this.onHand;
	 }
	 public void setOnHand(int onHand) {
		 this.onHand = onHand;
	 }
	 
	 /*
	  * Set and get purchase_price
	  */
	 public Double getPurchasePrice()
	 {   return purchasePrice;  }
	 public void setPurchasePrice(Double purchasePrice)
	 {   this.purchasePrice = purchasePrice;  }
	 
	 /*
	  * Set and get id
	  */
	 public Double getSalePrice()
	 {   return salePrice;  }
	 public void setSalePrice(Double salePrice)
	 {   this.salePrice = salePrice; }
	 
	 /*
	  * Set and get product_type
      */
	 public ProductType getProductType()
	 {   return productType;   }
	 public void setProductType(ProductType productType) {
		 this.productType = productType;
	 }
	 
	 /**
	  * @return categories associated
	  */
	 public Set<Category> getCategories() {
		 return this.categories;
	 }
	 
	 /**
	  * @param categories categories to set 
	  */
	 public void setCategories(Set<Category> categories) {
		 this.categories = categories;
	 }
	 
	 /**
	  * @return the product type attribute values
	  */
	 public Set<ProductTypeAttributeValue> getProductTypeAttributeValues() {
		 return this.productTypeAttributeValues;
	 }
	 
	 /**
	  * @param productTypeAttributeValues the set of product type attribute values to set
	  */
	 public void setProductTypeAttributeValues(
			 Set<ProductTypeAttributeValue> productTypeAttributeValues) {
		 this.productTypeAttributeValues = productTypeAttributeValues;
	 }
	 
	 /**
	  * @param productTypeAttributeValue the product type attribute value to add
	  */
	 public void addProductTypeAttributeValue(ProductTypeAttributeValue productTypeAttributeValue) {
		 this.productTypeAttributeValues.add(productTypeAttributeValue);
		 productTypeAttributeValue.setProduct(this);
	 }
	 
	 /**
	  * @param productTypeAttributeValue the product type attribute value to remove
	  */
	 public void removeProductTypeAttributeValue(
			 ProductTypeAttributeValue productTypeAttributeValue) {
		 this.productTypeAttributeValues.remove(productTypeAttributeValue);
		 productTypeAttributeValue.setProduct(null);
	 }
	 
	 @Id
	 @GeneratedValue(strategy=GenerationType.IDENTITY)
	 @Basic(optional=false)
	 @Column(name="id", nullable=false)
	 private int id;
	 @Column(name="name", length=255, nullable=false)
	 private String name;
	 @Column(name="sku", length=255, nullable=false)
	 private String sku;
	 
	 /*
	  * It seems we should use a CLOB object in database this way
	  * Reference: 
	  *  http://www.coderanch.com/t/318550/EJB-JEE/java/CLOBs-JPA
	  *  http://community.jboss.org/message/581248
	  */
	 @Lob
	 @Column(name="description", length=1048576, nullable=false)
	 private String description;
	 
	 @Column(name="purchase_price", length=10, nullable=false)
	 private Double purchasePrice;
	 @Column(name="sale_price", length=10, nullable=false)
	 private Double salePrice;
	 @Column(name="on_hand", nullable=false)
	 private int onHand;
	 
	 /*
	  * Many-to-one mapping from Product to ProductType
	  */
	 @ManyToOne(optional=false, fetch=FetchType.LAZY, cascade=CascadeType.ALL)
	 @JoinColumn(name="product_type", nullable=true)
	 private ProductType productType;
	 
	 /*
	  * One-to-many mapping from Product to ProductTypeAttributeValue
	  */
	 @OneToMany(mappedBy="product")
	 private Set<ProductTypeAttributeValue> productTypeAttributeValues 
	 	= new HashSet<ProductTypeAttributeValue>(); 
	 
	 /*
	  * Many-to-many mapping from Product to Category
	  */
	 @ManyToMany(cascade=CascadeType.ALL)
	 @JoinTable(
			name="product_categories",
			joinColumns=@JoinColumn(name="product_id", referencedColumnName="id"),
			inverseJoinColumns=@JoinColumn(name="category_id", referencedColumnName="id")
	 )
	 private Set<Category> categories = new HashSet<Category>();
}
